var com = {}; 
com.zpyr = {};

com.zpyr.Module = {};

var Module = com.zpyr.Module;

Module.NAME = "com.zpyr.Module";
Module.VERSION = 0.1;

Module.EXPORT_OK = ["createNamespace" , 
                    	// createNamespace( name , version ) : 주어진 name에 해당하는 네임스페이스를 생성하여 반환.
                    "isDefined" , 
                    	// isDefined( name ) : 주어진 이름을 가진 모듈이 정의되었는지 검사. 정의되어있다면 true 그렇지 않으면 false
                    "modules" , 
                    "getModuleNames" ,
                    "globalNamespace"];

Module.globalNamespace = this;
Module.modules = {"com.zpyr.Module": Module};


Module.createNamespace = function(name , version) {
	if(!name) throw new Error("com.zpyr.Module.createNamespace(): name required");
	// 문자열의 시작과 끝이 마침표이거나, 연속된 두개의 마침표가 존재하면 안된다.
	if(name.charAt(0) == '.' ||
	   name.charAt(name.length-1) == '.' ||
	   name.indexOf("..") != -1	) {
		throw new Error("com.zpyr.Module.createNamespace() : illegal name : " + name);
	}
	
	var parts = name.split('.');
	
	var container = Module.globalNamespace;

	// container - 전역변수 부터 시작하여, 그 하위로 parts 만큼 루프를 돌면서 part에 해당하는 object 생성.
	for( var i = 0 ; i < parts.length ; i++ ) {
		var part = parts[i];
		
		if(!container[part]) container[part] = {};
		else if(typeof container[part] != "object") {
			var n = parts.slice(0,i).join(',');
			throw new Error(n + " already exists and is not an object");
		}
		container = container[part];
	}
	
	var namespace = container;
	
	if(namespace.NAME) throw new Error("Module " + name + " is already defined");
	
	namespace.NAME = name;
	if(version) namespace.VERSION = version;
	
	Module.modules[name] = namespace;
	
	return namespace;
};

Module.isDefined = function(name) {
	return name in Module.modules;
};

Module.getModuleNames = function() {
	var pStr = '';
	for( var i in Module.modules ) {
		if(i != undefined) console.log(i);
	}
}

////////////////////////////////////////////////

Module.createNamespace("com.zpyr", "1.0");

com.zpyr.Class = function(opt) {
	
	var defs = com.zpyr.Class.defaults;
	var classname = opt.name;
	var superclass = opt.extend || defs.extend;
	var constructor = opt.construct || defs.construct;
	var methods = opt.methods || defs.methods;
	var statics = opt.statics || defs.statics;
	var borrows;
	var provides;
	
	if(!opt.borrows) borrows = [];
	else if( opt.borrows instanceof Array ) borrows = opt.borrows;
	else borrows = [ opt.borrows ];
	
	if(!opt.provides) provides = [];
	else if( opt.provides instanceof Array ) provides = opt.provides;
	else provides = [ opt.provides ];
	
	var proto = new superclass();
	for( var p in proto ) {
		if( proto.hasOwnProperty(p) ) {
			delete proto[p];
		}
	}
	
	for( var i = 0 ; i < borrows.length; i++ ) {
		var c = opt.borrows[i];
		borrows[i] = c;
		
		for( var p in c.prototype ) {
			console.log('borrow ' + 'type ' + typeof c.prototype[p] + ' ,val : ' + c.prototype[p]);
			if(typeof c.prototype[p] != 'function') continue;
			proto[p] = c.prototype[p];
		}
	}
	
	for (var p in methods) proto[p] = methods[p];
	
	proto.constructor = constructor;
	proto.superclass = superclass;
	if(classname) proto.classname = classname;
	
	for(var i = 0 ; provides.length; i++) {
		var c = provides[i];
		for(var p in c.prototype) {
			if(typeof c.prototype[p] != 'function') continue;
			if(p == 'constructor' || p == 'superclass') continue;
			
			if(p in proto && typeof proto[p] == 'function' &&
				proto[p].length == c.prototype[p].length) continue;
			throw new Error('Class' + classname + 'does not provide method' + c.classname + '.' + p);
		}
	}
	
	constructor.prototype = proto;
	
	for( var p in statics ) constructor[p] = data.statics[p];

	return constructor;
};
com.zpyr.Class.defaults = {
	extend : Object,
	construct : function() {},
	methods : {} ,
	statics : {}
};
